package ch.cryptobox.filehandles;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;

import org.acplt.oncrpc.OncRpcException;

import ch.cryptobox.nfsError.CreateFileException;
import ch.cryptobox.nfsError.FileNotFoundException;
import ch.cryptobox.nfsError.LookupException;
import ch.cryptobox.nfsError.ReadWriteException;
import ch.cryptobox.nfsclient.diropres;
import ch.cryptobox.nfsclient.fattr;
import ch.cryptobox.nfsclient.fhandle;
import ch.cryptobox.serivces.SynchronizationService;

public class FileHandle implements FileHandleI {
	static final int NFDIR = 2;
	static final int NFREG = 1;

	private final fhandle handle;
	private final fattr attributes;
	private final SynchronizationService nfs;
	private final String path;
	private final String name;


	public FileHandle(final SynchronizationService nfs) {
		this.nfs = nfs;
		handle = nfs.getRootDir();
		path = "";
		attributes = null;
		name = "~";

	}


	public FileHandle(final SynchronizationService nfs, final fhandle handle,  final fattr attributes, final String path, final String name) {
		this.nfs = nfs;
		this.handle = handle;


		if("".equals(name)){
			this.path = "";
			this.attributes = null;
			this.name = "~";
		}
		else
		{
			this.path = path;
			this.attributes = attributes;
			this.name = name;
		}

	}

	/* (non-Javadoc)
	 * @see ch.cryptobox.FileHandleI#isDirectory()
	 */
	@Override
	public boolean isDirectory() {
		//if null means is root
		return attributes == null || attributes.type == NFDIR;
	}
	
	/* (non-Javadoc)
	 * @see ch.cryptobox.FileHandleI#download()
	 */
	@Override
	public byte[] download() {
		 try {
			return nfs.readFile(this);
		} catch (OncRpcException | IOException | ReadWriteException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	//TODO fix for long paths requests
	/* (non-Javadoc)
	 * @see ch.cryptobox.FileHandleI#getFile(java.lang.String)
	 */
	@Override
	public FileHandleI getFile(final String relPath) {
		if("..".equals(relPath)) {
			if(isRoot()) return null;
			return getParent();
		}

		try {
			final diropres res = nfs.lookup(handle, relPath);
			if(0 != res.status) {
				System.out.println(FileHandle.class + ".getFile() wrong status" + res.status);
				return null;
			}





			final int index = relPath.lastIndexOf(File.separator);


			final String fileName = relPath.substring(index == -1? 0 : (index + 1), relPath.length());
			return new FileHandle(nfs, res.diropok.file, res.diropok.attributes, path + File.separator + relPath, fileName );

		} catch (final Exception ex){	
			ex.printStackTrace();
		}

		return null;
	}
	

	/* (non-Javadoc)
	 * @see ch.cryptobox.FileHandleI#getDirectory(java.lang.String)
	 */
	@Override
	public FileHandleI getDirectory(final String relPath) {
		if("..".equals(relPath)) {
			if(isRoot()) return null;
			return getParent();
		}

		try {
			final diropres res = nfs.changeDir(handle, relPath);
			if(0 != res.status) {
				System.out.println(FileHandle.class + ".getFile() wrong status" + res.status);
				return null;
			}





			final int index = relPath.lastIndexOf(File.separator);


			final String fileName = relPath.substring(index == -1? 0 : (index + 1), relPath.length());
			return new FileHandle(nfs, res.diropok.file, res.diropok.attributes, path + File.separator + relPath, fileName );




		} catch (OncRpcException | IOException | CreateFileException
				| FileNotFoundException e) {
		//	e.printStackTrace();
		
		}

		return null;
	}

	/* (non-Javadoc)
	 * @see ch.cryptobox.FileHandleI#isRoot()
	 */
	@Override
	public boolean isRoot() {
		return attributes==null;
	}


	/* (non-Javadoc)
	 * @see ch.cryptobox.FileHandleI#getFiles()
	 */
	@Override
	public ArrayList<FileHandleI> getFiles() {
		if(!isDirectory()) 
			return null;

//		System.out.println("FileHandle.getFiles() " + getPath());
		
		final ArrayList<FileHandleI> files = new ArrayList<FileHandleI>();
		try {
			final ArrayList<String> strings = nfs.readDir(handle);
			for(final String s : strings) {
				final diropres res = nfs.lookup(handle, s);
				if(0 != res.status) {
					System.out.println(FileHandle.class + ".getFiles() wrong status" + res.status);
					continue;
				}

				files.add( new FileHandle(nfs, res.diropok.file, res.diropok.attributes, this.path + File.separator + s, s ));

			}
		} catch (LookupException | OncRpcException | IOException e) {
			e.printStackTrace();
		}

		return files;
	}

	/* (non-Javadoc)
	 * @see ch.cryptobox.FileHandleI#getParent()
	 */
	@Override
	public FileHandleI getParent() {
		try {
			final diropres res = nfs.changeDir(handle, "..");
			if(0 != res.status) {
				System.out.println(FileHandle.class + ".getParent() wrong status" + res.status);
				return null;
			}



			final String filePath = path.substring(0, path.lastIndexOf(File.separator));

			return new FileHandle(nfs, res.diropok.file, res.diropok.attributes, filePath, filePath.substring( filePath.lastIndexOf(File.separator) + 1, filePath.length()) );

		} catch (OncRpcException | IOException | CreateFileException
				| FileNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}


	/* (non-Javadoc)
	 * @see ch.cryptobox.FileHandleI#toString()
	 */
	@Override
	public String toString() {
		return name+(isDirectory()?"/":"");
	}

	/* (non-Javadoc)
	 * @see ch.cryptobox.FileHandleI#getName()
	 */
	@Override
	public String getName() {
		return name;
	}


	/* (non-Javadoc)
	 * @see ch.cryptobox.FileHandleI#getPath()
	 */
	@Override
	public String getPath() {
		return path;
	}


	/* (non-Javadoc)
	 * @see ch.cryptobox.FileHandleI#getHandle()
	 */

	public fhandle getHandle() {
		return handle;
	}


	/* (non-Javadoc)
	 * @see ch.cryptobox.FileHandleI#getDate()
	 */
	@Override
	public Date getDate() {
		return new Date((long)attributes.mtime.seconds*(long)1000);
	}
}
